LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

ENTITY TankMatch IS
	PORT(
		-- Clock and Reset Ports
		Clk   : IN std_logic;
		Reset : IN std_logic;

		-- Control Ports
		GameMap : IN std_logic_vector(1 downto 0);
		-- Display Ports
		HoriSync  : OUT std_logic;
		VertiSync : OUT std_logic;
		Red, Green, Blue : OUT std_logic_vector(2 DOWNTO 0);
		-- PS/2 Ports
		PS2DataIn : IN std_logic;
		PS2ClkIn  : IN std_logic; -- PS2 clk and data
		-- COM Ports
		COMClk : IN std_logic;
		Txd : OUT std_logic;
		Rxd : IN std_logic;
		
		KeyStateDis : OUT std_logic_vector(5 downto 0);
		
		TempKeyIn : IN std_logic_vector(5 downto 0);
		DebugSignal : OUT std_logic_vector(2 downto 0);
		HandClk : IN std_logic
	);
END TankMatch;

ARCHITECTURE rtl OF TankMatch IS
	COMPONENT DispClkGen IS
	PORT
	(
		areset		: IN STD_LOGIC;
		inclk0		: IN STD_LOGIC;
		c0		: OUT STD_LOGIC ;
		c1		: OUT STD_LOGIC ;
		locked		: OUT STD_LOGIC 
	);
	END COMPONENT;

	COMPONENT PrimRAM IS
	PORT
	(
		address_a		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
		address_b		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
		clock_a		: IN STD_LOGIC ;
		clock_b		: IN STD_LOGIC ;
		data_a		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
		data_b		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
		wren_a		: IN STD_LOGIC  := '1';
		wren_b		: IN STD_LOGIC  := '1';
		q_a		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
		q_b		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0)
	);
	END COMPONENT;
	
	COMPONENT SecoRAM IS
	PORT
	(
		address_a		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
		address_b		: IN STD_LOGIC_VECTOR (9 DOWNTO 0);
		clock_a		: IN STD_LOGIC ;
		clock_b		: IN STD_LOGIC ;
		data_a		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
		data_b		: IN STD_LOGIC_VECTOR (15 DOWNTO 0);
		wren_a		: IN STD_LOGIC  := '1';
		wren_b		: IN STD_LOGIC  := '1';
		q_a		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
		q_b		: OUT STD_LOGIC_VECTOR (15 DOWNTO 0)
	);
	END COMPONENT;
	
	COMPONENT KeyCoder IS
	PORT(
		DataIn, PSClk : IN std_logic;
		Clk, Reset : IN std_logic;
		P1KeyState : OUT std_logic_vector(5 downto 0);
		P2KeyState : OUT std_logic_vector(5 downto 0)
	);
	END COMPONENT;
	
	COMPONENT GameControl IS
	PORT(
		Clk : IN std_logic;
		ClkDispEle : IN std_logic;
		Start : IN std_logic;
		Finish : OUT std_logic;
		Reset : IN std_logic;
		Pause : OUT std_logic;
		
		GameMode : IN std_logic_vector(1 downto 0);
		GameMap : IN std_logic_vector(1 downto 0);
		GameResult : OUT std_logic_vector(1 DOWNTO 0);

		PrimAddr    : OUT std_logic_vector(9 downto 0);
		PrimReadData    : IN  std_logic_vector(15 downto 0);
		PrimWriteData	: OUT std_logic_vector(15 downto 0);
		PrimWriteEnable	: OUT std_logic;
		SecoAddr   : OUT std_logic_vector(9 downto 0);
		SecoWriteData   : OUT std_logic_vector(15 downto 0);
		SecoWriteEnable : OUT std_logic;
		SecoReadData    : IN  std_logic_vector(15 downto 0);
		
		RawP1Key : IN std_logic_vector(5 downto 0);	
		RawP2Key : IN std_logic_vector(5 downto 0);
		
		oP1HP, oP2HP : OUT std_logic_vector(1 DOWNTO 0);
		
		GameResultInput : IN std_logic_vector(1 DOWNTO 0);
		RandomIn : IN std_logic_vector(15 DOWNTO 0);
		RandomIn2 : IN std_logic_vector(15 downto 0);
		
		stateout : OUT std_logic_vector(2 downto 0);
		DirOut : out std_logic_vector(2 downto 0)
	);
	END COMPONENT;
	
	COMPONENT Welcome IS
	PORT(
		Clk : IN std_logic;
		Start : IN std_logic;
		Finish : OUT std_logic;
		Reset : IN std_logic;
		
		GameMode : OUT std_logic_vector(1 downto 0);
		
		PrimAddr    : OUT std_logic_vector(9 downto 0);
		PrimWriteData    : OUT  std_logic_vector(15 downto 0);
		PrimWriteEnable  : OUT std_logic;

		RawP1Key : IN std_logic_vector(5 downto 0);
		CurSelect : OUT std_logic_vector(1 DOWNTO 0);
		
DebugSignal : OUT std_logic_vector(2 DOWNTO 0)
	);
	END COMPONENT;
	
	COMPONENT GameOver IS
	PORT(
		Clk : IN std_logic;
		Start : IN std_logic;
		Finish : OUT std_logic;
		Reset : IN std_logic;
		
		--GameMode : IN std_logic_vector(1 downto 0);
		GameResult : IN std_logic_vector(1 DOWNTO 0);
		
		PrimAddr    : OUT std_logic_vector(9 downto 0);
		PrimWriteData    : OUT  std_logic_vector(15 downto 0);
		PrimWriteEnable  : OUT std_logic;

		RawP1Key : IN std_logic_vector(5 downto 0)
	);
	END COMPONENT;

	COMPONENT Display IS
	PORT(
		Clk : IN std_logic;
		Reset : IN std_logic;
		GameResult : IN std_logic_vector(1 DOWNTO 0);
		PrimReadAddr : OUT std_logic_vector(9 DOWNTO 0);
		PrimReadData : IN std_logic_vector(15 DOWNTO 0);
		hs  : OUT std_logic;
		vs : OUT std_logic;
		ClkEleRom : IN std_logic;
		r, g, b : OUT std_logic_vector(2 DOWNTO 0);
		DispStateCon : IN std_logic;
		DispStatePau : IN std_logic;
		P1HP, P2HP : IN std_logic_vector(1 DOWNTO 0);
		CurSelect : IN std_logic_vector(1 DOWNTO 0);
		GameOverDis : IN std_logic
	);
	END COMPONENT;
	
	COMPONENT Communication IS
	PORT(
		Clk : IN std_logic;
		Reset : IN std_logic;
		
		GameMode : IN std_logic_vector(1 downto 0);
		-- Key Switch
		LocalP2KeyState : IN std_logic_vector(5 DOWNTO 0);
		P2KeyState : OUT std_logic_vector(5 DOWNTO 0);
		-- COM Ports
		RxD : IN std_logic;
		TxD : OUT std_logic;
		-- SecoRam Switch
		SecoAddr    	: OUT std_logic_vector(9 downto 0);
		SecoReadData 	: IN std_logic_vector(15 DOWNTO 0);
		SecoWriteData   : OUT  std_logic_vector(15 downto 0);
		SecoWriteEnable : OUT std_logic;
		DebugSignal : OUT std_logic_vector(2 DOWNTO 0)
	);
	END COMPONENT;
	
	COMPONENT TestRandom IS
	port 
	(
		Clk		: in std_logic;
		Reset	: in std_logic;
		sr_out	: out std_logic_vector(15 DOWNTO 0)
	);
	END COMPONENT;

	TYPE State_Type IS (Idle,
						Init,
						WelcomeChoice,
						GameCon,
						GameOvered);
	SIGNAL state : State_Type;
	
	SIGNAL WelGameMode : std_logic_vector(1 DOWNTO 0);
	SIGNAL GameMode : std_logic_vector(1 downto 0);
	--SIGNAL GameMap : std_logic_vector(1 downto 0);
	SIGNAL P1KeyState : std_logic_vector(5 downto 0);
	SIGNAL P2KeyState : std_logic_vector(5 downto 0);
	SIGNAL GameResult : std_logic_vector(1 DOWNTO 0);
	--Sub statemachine control
	SIGNAL WelcomeStart, WelcomeFinish: std_logic;
	SIGNAL GameControlStart, GameControlFinish : std_logic;
	SIGNAL GameOverStart, GameOverFinish : std_logic;
	--Clock port
	SIGNAL ClkMain : std_logic;
	SIGNAL ClkMainMem : std_logic;
	SIGNAL ClkDisp : std_logic;
	SIGNAL ClkDispMem : std_logic;
	SIGNAL ClkCOM  : std_logic;	-- to com memory
	SIGNAL ConRomClk : std_logic;

	SIGNAL ClkPLL32 : std_logic;
	SIGNAL ClkPLL32Counter : std_logic_vector(15 DOWNTO 0);
	SIGNAL ClkPLL : std_logic;
	--SIGNAL ClkD
	-- Primary Memory
	SIGNAL PrimAddr   : std_logic_vector(9 downto 0);
	SIGNAL PrimWriteData   : std_logic_vector(15 downto 0);
	SIGNAL PrimWriteEnable : std_logic;
	SIGNAL PrimReadData    : std_logic_vector(15 downto 0);

	SIGNAL PrimAddr_GCon   : std_logic_vector(9 downto 0);
	SIGNAL PrimWriteData_GCon   : std_logic_vector(15 downto 0);
	SIGNAL PrimWriteEnable_GCon : std_logic;
	SIGNAL PrimAddr_Wel   : std_logic_vector(9 downto 0);
	SIGNAL PrimWriteData_Wel   : std_logic_vector(15 downto 0);
	SIGNAL PrimWriteEnable_Wel : std_logic;
	SIGNAL PrimAddr_Ovr   : std_logic_vector(9 downto 0);
	SIGNAL PrimWriteData_Ovr   : std_logic_vector(15 downto 0);
	SIGNAL PrimWriteEnable_Ovr : std_logic;
	
	TYPE PrimSel_Type IS (SelWelcome,SelGameCon, SelGameOver);
	SIGNAL PrimSel : PrimSel_Type;
	
	-- Primary Memory Display part
--	SIGNAL DispWriteEnable : OUT std_logic;
	SIGNAL DispAddr    : std_logic_vector(9 downto 0);
	SIGNAL DispData    : std_logic_vector(15 downto 0);
	-- Seconary Memory
	SIGNAL SecoAddr   : std_logic_vector(9 downto 0);
	SIGNAL SecoWriteData   : std_logic_vector(15 downto 0);
	SIGNAL SecoWriteEnable : std_logic;
	SIGNAL SecoReadData    : std_logic_vector(15 downto 0);
	-- Seconary Memory COM Part
	SIGNAL COMAddr   : std_logic_vector(9 downto 0);
	SIGNAL COMWriteData   : std_logic_vector(15 downto 0);
	SIGNAL COMWriteEnable : std_logic;
	SIGNAL COMReadData    : std_logic_vector(15 downto 0);

	SIGNAL LocalP2KeyState : std_logic_vector(5 DOWNTO 0);
	
	SIGNAL ClkEleRom : std_logic;
	
	SIGNAL DispStateCon : std_logic;
	SIGNAL DispStatePau : std_logic;
	SIGNAL P1HP, P2HP : std_logic_vector(1 DOWNTO 0);
	
	SIGNAL DirState : std_logic_vector(2 downto 0);
	SIGNAL WelcomeCurSelect : std_logic_vector(1 DOWNTO 0);
	
	SIGNAL GameResultInput : std_logic_vector(1 DOWNTO 0);
	SIGNAL RandomGen : std_logic_vector(15 DOWNTO 0);
	
	SIGNAL GameOverDis : std_logic;
	
	signal tcounter : std_logic_vector(30 downto 0);
	
BEGIN
	uDispClkGen : DispClkGen PORT MAP(
		areset => '0',
		inclk0 => Clk,
		c0	=> ClkPLL,
		c1	=> ClkEleRom );

	uPrimaryRAM : PrimRAM PORT MAP(
		address_a => PrimAddr,
		address_b => DispAddr,
		clock_a => ClkDispMem,
		clock_b	=> ClkMainMem,
		data_a	=> PrimWriteData,
		data_b	=> (OTHERS => '0'),	-- unused port
		wren_a	=> PrimWriteEnable,
		wren_b	=> '0',
		q_a	=> PrimReadData,
		q_b	=> DispData );
	
	uSeconaryRAM : SecoRAM PORT MAP(
		address_a	=> SecoAddr,
		address_b	=> COMAddr,
		clock_a	=> ClkMainMem,
		clock_b	=> ClkCOM,
		data_a	=> SecoWriteData,
		data_b	=> COMWriteData,
		wren_a	=> SecoWriteEnable,
		wren_b	=> COMWriteEnable,
		q_a	=> SecoReadData,
		q_b	=> COMReadData );
		
	cKeyCoder : KeyCoder PORT MAP(
		DataIn	=> PS2DataIn,
		PSClk	=> PS2ClkIn,
		Clk	=> ClkPLL,
		Reset => Reset,
		P1KeyState => P1KeyState,
		P2KeyState => LocalP2KeyState );
		
	cCommunication : Communication PORT MAP(
		Clk => COMClk,
		Reset => Reset,
		GameMode => GameMode,
		-- Key Switch
		LocalP2KeyState => LocalP2KeyState,
		P2KeyState => P2KeyState,
		-- COM Ports
		RxD => RxD,
		TxD => TxD,
		-- SecoRam Switch
		SecoAddr    	=> COMAddr,
		SecoReadData 	=> COMReadData,
		SecoWriteData   => COMWriteData,
		SecoWriteEnable => COMWriteEnable);--,
--				DebugSignal => DebugSignal );
--	P2KeyState <= LocalP2KeyState;

	cGameControler : GameControl PORT MAP(
		Clk => ClkMain,
		ClkDispEle => ConRomClk,
		Start => GameControlStart,
		Finish => GameControlFinish,
		Reset => Reset,
		Pause => DispStatePau,
		GameMode => GameMode,
		GameMap	=> GameMap,
		GameResult => GameResult,
		------
		PrimAddr	=> PrimAddr_GCon,	-- prim address and writedata writeenable are c....
		PrimReadData	=> PrimReadData,
		PrimWriteData	=> PrimWriteData_GCon,
		PrimWriteEnable	=> PrimWriteEnable_GCon,
		SecoAddr	=> SecoAddr,
		SecoWriteData	=> SecoWriteData,
		SecoWriteEnable	=> SecoWriteEnable,
		SecoReadData	=> SecoReadData,
		------
		RawP1Key => P1KeyState,
		RawP2Key => P2KeyState,
		
		oP1HP => P1HP,
		oP2HP => P2HP,
		
		GameResultInput => GameResultInput,
		
		RandomIn => RandomGen,
		RandomIn2 => ClkPLL32Counter,
		
		stateout => DebugSignal );
		--DirOut => DebugSignal );
	
	cWelcome : Welcome PORT MAP(
		Clk => ClkMain,
		Start => WelcomeStart,
		Finish => WelcomeFinish,
		Reset => Reset,
		
		GameMode => WelGameMode,
		
		PrimAddr	=> PrimAddr_Wel,
		PrimWriteData	=> PrimWriteData_Wel,
		PrimWriteEnable => PrimWriteEnable_Wel,

		RawP1Key => P1KeyState,
		CurSelect => WelcomeCurSelect
--		DirState => DirState
--		DebugSignal => DebugSignal
		 );
	--DirStateDisp => DebugSignal

	cGameOver : GameOver PORT MAP(
		Clk => ClkMain,
		Start => GameOverStart,
		Finish => GameOverFinish,
		Reset => Reset,

		GameResult => GameResult,
		
		PrimAddr	=> PrimAddr_Ovr,
		PrimWriteData	=> PrimWriteData_Ovr,
		PrimWriteEnable => PrimWriteEnable_Ovr,

		RawP1Key => P1KeyState );

	cDisplay : Display PORT MAP(
		Clk 	=> ClkDisp,
--		Clk => Clk,
		Reset 	=> Reset,
		GameResult => GameResult,
		PrimReadAddr => DispAddr,
		PrimReadData => DispData,
		hs	=> HoriSync,
		vs	=> VertiSync,
		ClkEleRom => ClkEleRom,
		r => Red,
		g => Green,
		b => Blue,
		DispStateCon => DispStateCon,
		DispStatePau => DispStatePau,		
		P1HP => P1HP,
		P2HP => P2HP,
		CurSelect => WelcomeCurSelect,
		GameOverDis => GameOverDis );
		
	cRand : TestRandom PORT MAP(
		Clk => ClkPLL,
		Reset	=> Reset,
		sr_out	=> RandomGen );

	---- Clock Configuration ----
	ClkDisp <= ClkPLL;
	ClkDispMem <= ClkMainMem;--ClkEleRom;--ClkPLL;--PLL;
	
	ClkCOM <= ClkMainMem;--ClkEleRom;--ClkPLL;--COMClk;
	ClkMainMem <= ClkEleRom;--ClkPLL;--PLL;
	ConRomClk <= ClkEleRom;
	
	ClkMain <= tcounter(6);--ClkPLL32;


	KeyStateDis <= P2KeyState;
--	DebugSignal(0) <= DispStatePau;

	--- DirState For Welcome Module
	DirState <=  "011" WHEN P1KeyState(3) = '1' ELSE
				 "010" WHEN P1KeyState(2) = '1' ELSE
				 "001" WHEN P1KeyState(1) = '1' ELSE
				 "000" WHEN P1KeyState(0) = '1' ELSE
				 "100";
	
	c32dClk : PROCESS(ClkPLL, Reset)
	BEGIN
	  IF Reset = '0' THEN
	    ClkPLL32Counter <= (OTHERS => '0');
	  ELSIF rising_edge(ClkPLL) THEN
	    ClkPLL32Counter <= ClkPLL32Counter +1;
	  END IF;
	END PROCESS;
	ClkPLL32 <= ClkPLL32Counter(4);
	
	c2dClk : PROCESS(ClkPLL, Reset)
	BEGIN
	  IF Reset = '0' THEN
	    tcounter <= (others => '0');
	  ELSIF rising_edge(ClkPLL) THEN
	    tcounter <= tcounter +1;
	  END IF;
	END PROCESS;
	
	
	PrimAddr <= PrimAddr_GCon WHEN PrimSel = SelGameCon ELSE
				PrimAddr_Wel  WHEN PrimSel = SelWelcome ELSE
				PrimAddr_Ovr;
				
	PrimWriteData <= PrimWriteData_GCon WHEN PrimSel = SelGameCon ELSE
					 PrimWriteData_Wel  WHEN PrimSel = SelWelcome ELSE
					 PrimWriteData_Ovr;
					 
	PrimWriteEnable <= PrimWriteEnable_GCon WHEN PrimSel = SelGameCon ELSE
					   PrimWriteEnable_Wel  WHEN PrimSel = SelWelcome ELSE
					   PrimWriteEnable_Ovr;
	
	PROCESS(ClkMain, Reset)
	BEGIN
		IF Reset = '0' THEN
			state <= Idle;
			DispStateCon <= '0';
			GameMode <= "00";
			GameOverDis <= '0';
		ELSIF rising_edge(ClkMain) THEN
			CASE state IS
				WHEN Idle =>
					state <= Init;
					GameMode <= "00";
					WelcomeStart <= '1';
					PrimSel <= SelWelcome;
					DispStateCon <= '0';
				WHEN Init =>
					WelcomeStart <= '0';
					IF WelcomeFinish = '1' THEN
						state <= GameCon;
						GameMode <= WelGameMode;
						GameControlStart <= '1';
						PrimSel <= SelGameCon;
						DispStateCon <= '1';
					END IF;
				WHEN GameCon =>
					GameControlStart <= '0';
					IF GameControlFinish = '1' THEN
						state <= GameOvered;
						GameOverDis <= '1';
						GameMode <= "00";
						GameOverStart <= '1';
						PrimSel <= SelGameOver;
					ELSE
						state <= GameCon;
					END IF;
				WHEN GameOvered =>
					GameOverStart <= '0';
					IF GameOverFinish = '1' THEN
						state <= Idle;
						GameOverDis <= '0';
					ELSE
						state <= GameOvered;
					END IF;
				WHEN OTHERS =>
			END CASE;
		END IF;
	END PROCESS;

END rtl;

